package main

import (
	"encoding/json"
	"fmt"
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
	"log"
	"net"
	"os"
	"time"
)

var mapUsers map[string]int
var ip, port *walk.LineEdit
var cl *walk.TextEdit
var status *walk.Label
var conns map[string]net.Conn
var l net.Listener

func main() {
	var start, stop *walk.PushButton
	file, _ := os.OpenFile("err.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	logger := log.New(file, "", log.LstdFlags|log.Llongfile)
	logger.Println("main start")
	MainWindow{
		Title:   "golang聊天室server端",
		MinSize: Size{656, 326},
		Layout:  VBox{},
		Children: []Widget{
			Label{
				Text: "go开发的聊天室(服务端)v1.1",
			},

			Composite{
				Layout:  HBox{},
				MaxSize: Size{100, 60},
				Children: []Widget{
					Label{
						Text: "服务ip:",
					},
					LineEdit{
						AssignTo: &ip,
						MaxSize:  Size{100, 60},
						Text:     "10.15.54.16",
					},
					Label{
						Text: "端口:",
					},
					LineEdit{
						AssignTo: &port,
						MaxSize:  Size{60, 60},
						Text:     "61168",
					},
					PushButton{
						AssignTo: &start,
						Text:     "启动",
						OnClicked: func() {
							//fmt.Println("select:", cbox.Text())
							font := status.Font()
							newFont, _ := walk.NewFont(font.Family(), font.PointSize(), walk.FontBold)
							status.SetFont(newFont)
							go StartServer()
							start.SetEnabled(false)
							stop.SetEnabled(true)
						},
					},
					PushButton{
						AssignTo: &stop,
						Enabled:  false,
						Text:     "停止",
						OnClicked: func() {
							os.Exit(0)
							/*				go func() {
											for _, value := range conns {
												value.Close()
											}

											if status != nil {
												status.SetText("已关闭")
											}

											if stop != nil {
												stop.SetEnabled(false)
												start.SetEnabled(true)
											}
										}()*/

						},
					},
				},
			},
			Composite{
				Layout:  HBox{},
				MaxSize: Size{100, 60},
				Children: []Widget{
					Label{
						Text: "状态:",
					},
					Label{
						AssignTo: &status,
						Text:     "",
					},
					HSpacer{
						ColumnSpan: 4,
					},
				},
			},

			TextEdit{
				MinSize:  Size{100, 300},
				AssignTo: &cl,
				ReadOnly: true,
				Text:     "",
			},
		},
	}.Run()
}

type ClientMsg struct {
	Type       string
	UserName   string
	ToUserName string
	Content    string
}

type Msg struct {
	Type       string
	UserName   string
	ToUserName string
	Content    string
	DateTime   string
	List       map[string]int
}

//群发功能
func checkError(err error, info string) (res bool) {

	if err != nil {
		apendMsg(info + "  " + err.Error())
		return false
	}
	return true
}

func updateList(messages chan string) {
	strList := Msg{"list", "", "", "", getDateTeme(), mapUsers}
	ulistStr, err := json.Marshal(strList)
	//fmt.Println("this is my debug ", string(ulistStr))
	if err != nil {
		fmt.Println("userlist josn Error %s", err.Error())
	} else {
		messages <- string(ulistStr)
	}
}

func joinNotic(userName string, messages chan string) {
	apendMsg(userName + "进入了系统")
	strList := Msg{"join", userName, "", "", getDateTeme(), nil}
	ulistStr, err := json.Marshal(strList)
	if err != nil {
		fmt.Println("joinNotic josn Error %s", err.Error())
	} else {
		messages <- string(ulistStr)
	}
}

func sendIp(messages chan string, userName string) {
	msg := Msg{"ip", userName, "", "", "", nil}
	jsonStr, err := json.Marshal(msg)
	if err != nil {
		fmt.Println("sendIp josn Error %s", err.Error())
	} else {
		messages <- string(jsonStr)
	}
	updateList(messages)
}

func sendErr(messages chan string, ToUserName string, errmsg string) {
	msg := Msg{"err", "system", ToUserName, errmsg, getDateTeme(), nil}
	jsonStr, err := json.Marshal(msg)
	if err != nil {
		fmt.Println("sendErr josn Error %s", err.Error())
	} else {
		messages <- string(jsonStr)
	}
}

func Handler(conn net.Conn, messages chan string) {
	userName := conn.RemoteAddr().String()
	if _, ok := mapUsers[userName]; ok == false {
		mapUsers[userName] = 1
	}
	go sendIp(messages, userName)
	go joinNotic(userName, messages)
	apendMsg("connection is connected from " + userName)
	buf := make([]byte, 4096)
	for {
		lenght, err := conn.Read(buf)
		if checkError(err, "Connection") == false {
			if _, ok := mapUsers[userName]; ok {
				//fmt.Println("begin ", mapUsers)
				delete(mapUsers, userName)
				//fmt.Println("end ", mapUsers)
				go updateList(messages)
				msg := Msg{"out", userName, "", "", getDateTeme(), nil}
				jsonStr, err := json.Marshal(msg)
				if err != nil {
					fmt.Println("out josn Error %s", err.Error())
				} else {
					apendMsg(userName + "离开了系统")
					messages <- string(jsonStr)
				}
			}
			conn.Close()
			break
		}
		if lenght > 0 {
			buf[lenght] = 0
		}

		if lenght > 1024 {
			sendErr(messages, userName, "输入内容太长")
			continue
		}

		fmt.Println("Rec[", conn.RemoteAddr().String(), "] Say :", string(buf[0:lenght]))
		reciveStr := string(buf[0:lenght])
		var m ClientMsg
		err1 := json.Unmarshal([]byte(reciveStr), &m)
		if err1 != nil {
			fmt.Println("decode msg Error %s", err.Error())
		} else {
			if m.Type == "msg" {
				if m.ToUserName == "---所有人---" {
					msg := Msg{"msg", userName, "", m.Content, getDateTeme(), nil}
					jsonStr, err := json.Marshal(msg)
					if err != nil {
						fmt.Println("josn Error %s", err.Error())
					} else {
						messages <- string(jsonStr)
					}
				} else if m.ToUserName != "" && userName != m.ToUserName {
					msg := Msg{"msgTo", userName, m.ToUserName, m.Content, getDateTeme(), nil}
					jsonStr, err := json.Marshal(msg)
					if err != nil {
						fmt.Println("josn Error %s", err.Error())
					} else {
						messages <- string(jsonStr)
					}
				}

			}
		}

	}
}

func getDateTeme() string {
	var t int64 = time.Now().Unix()
	var s string = time.Unix(t, 0).Format("2006-01-02 15:04:05")
	return s
}

func echoHandler(conns map[string]net.Conn, messages chan string) {
	for {
		msg := <-messages
		apendMsg(msg)
		var m Msg
		err := json.Unmarshal([]byte(msg), &m)
		if err != nil {
			fmt.Println("showMsg Error %s", err.Error())
		} else {
			if m.Type == "msgTo" {
				if v, ok := conns[m.UserName]; ok {
					v.Write([]byte(msg))
				}
				if v, ok := conns[m.ToUserName]; ok {
					v.Write([]byte(msg))
				}
			} else if m.Type == "ip" {
				if v, ok := conns[m.UserName]; ok {
					v.Write([]byte(msg))
				}
			} else if m.Type == "err" && m.ToUserName != "" {
				if v, ok := conns[m.ToUserName]; ok {
					v.Write([]byte(msg))
				}
			} else {
				//fmt.Println(msg)
				for key, value := range conns {
					//fmt.Println("connection is connected from ...", key)
					_, err := value.Write([]byte(msg))
					if err != nil {
						fmt.Println(err.Error())
						delete(conns, key)
						//delete(mapUsers, value.RemoteAddr().String())
					}

				}
			}

		}

	}

}

func StartServer() {
	ipText := ip.Text()
	portText := port.Text()
	if ipText != "" && portText != "" {
		status.SetText("正在启动...")
		fmt.Println("ip is ", ipText+":"+portText)
		var err error
		l, err = net.Listen("tcp", ipText+":"+portText)
		checkError(err, "start listen")
		if err != nil {
			status.SetText("启动失败...")
			return
		}
		status.SetText("运行中...")
		apendMsg("等待客户端链接 ...")
		conns = make(map[string]net.Conn)
		messages := make(chan string, 10)
		mapUsers = map[string]int{}

		//启动服务器广播线程
		go echoHandler(conns, messages)
		for {
			conn, err := l.Accept()
			checkError(err, "Accept")
			conns[conn.RemoteAddr().String()] = conn
			//启动一个新线程
			go Handler(conn, messages)

		}
	} else {
		apendMsg("Err:参数为空...")
	}

}

func apendMsg(msg string) {
	if cl != nil {
		cl.AppendText("[" + getDateTeme() + "] " + msg + "\r\n")
	}
}
